package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.schedulerEvent.SchedulerEventService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.schedule.SchedulerSystem;
import org.thingsboard.server.schedule.core.DefaultScheduleSystem;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;

import java.util.List;


/**
 * 调度controller
 */
@RestController
@TbCoreComponent
@RequestMapping("/api")
public class SchedulerController extends BaseController{
    public static final String SCHEDULER_EVENT_ID = "schedulerEventId";
    @Autowired
    private SchedulerEventService schedulerEventService;

    @Autowired
    private SchedulerSystem defaultSchedulerSystem;

    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
    @RequestMapping(value = "/schedulerEvent", method = RequestMethod.POST)
    @ResponseBody
    public SchedulerEvent saveSchedulerEvent(@RequestBody SchedulerEvent se) throws ThingsboardException {
        try {
            // 设置租户ID
            se.setTenantId(getCurrentUser().getTenantId());
            // 权限检查
            checkEntity(se.getId(), se, Resource.SCHEDULER_EVENT);
            //保存
            SchedulerEvent savedSe = checkNotNull(schedulerEventService.saveSchedulerEvent(se));
            defaultSchedulerSystem.onSchedulerEventChange(savedSe,se.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
            //操作日志
            logEntityAction(savedSe.getId(), savedSe,
                    null,
                    se.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
            return savedSe;
        } catch (Exception e) {
            logEntityAction(emptyId(EntityType.SCHEDULER_EVENT), se,
                    null, se.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
            throw handleException(e);
        }
    }


    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
    @RequestMapping(value = "/schedulerEventInfo", method = RequestMethod.POST)
    @ResponseBody
    public SchedulerEventInfo saveSchedulerEventInfo(@RequestBody SchedulerEventInfo schedulerEventInfo) throws ThingsboardException {
        try {
            // 设置租户ID
            schedulerEventInfo.setTenantId(getCurrentUser().getTenantId());
            // 权限检查
            checkEntity(schedulerEventInfo.getId(), schedulerEventInfo, Resource.SCHEDULER_EVENT);
            //保存
            SchedulerEventInfo savedSe = checkNotNull(schedulerEventService.saveSchedulerEventInfo(schedulerEventInfo));

            defaultSchedulerSystem.onSchedulerEventInfoChange(savedSe,schedulerEventInfo.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
            //操作日志
            logEntityAction(savedSe.getId(), savedSe,
                    null,
                    schedulerEventInfo.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
            return savedSe;
        } catch (Exception e) {
            logEntityAction(emptyId(EntityType.SCHEDULER_EVENT), schedulerEventInfo,
                    null, schedulerEventInfo.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
            throw handleException(e);
        }
    }

    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
    @RequestMapping(value = "/schedulerEvent/trigger/{schedulerEventId}", method = RequestMethod.GET)
    @ResponseBody
    public void triggerSchedulerEvent(@PathVariable(SCHEDULER_EVENT_ID) String strSchedulerEventId) throws ThingsboardException {
        checkParameter(SCHEDULER_EVENT_ID, strSchedulerEventId);
        try {
            SchedulerEventId schedulerEventId = new SchedulerEventId(toUUID(strSchedulerEventId));
            SchedulerEventInfo schedulerEventInfo= checkSchedulerEventInfoId(schedulerEventId, Operation.SCHEDULER_EVENT_TRIGGER);
            defaultSchedulerSystem.triggerSchedulerEvent(schedulerEventInfo);
            logEntityAction(schedulerEventInfo.getId(), schedulerEventInfo,
                    null,
                    ActionType.SCHEDULER_EVENT_MAN_TRIG, null);
        } catch (Exception e) {
            logEntityAction(emptyId(EntityType.SCHEDULER_EVENT),
                    null,
                    null,
                    ActionType.SCHEDULER_EVENT_MAN_TRIG, e, strSchedulerEventId);
            throw handleException(e);
        }
    }



    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
    @RequestMapping(value = "/schedulerEvent/{schedulerEventId}", method = RequestMethod.GET)
    @ResponseBody
    public SchedulerEvent getSchedulerEventById(@PathVariable(SCHEDULER_EVENT_ID) String strDeviceId) throws ThingsboardException {
        checkParameter(SCHEDULER_EVENT_ID, strDeviceId);
        try {
            SchedulerEventId schedulerEventId = new SchedulerEventId(toUUID(strDeviceId));
            return checkSchedulerEventId(schedulerEventId, Operation.READ);
        } catch (Exception e) {
            throw handleException(e);
        }
    }



    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
    @RequestMapping(value = "/schedulerEvent/types", method = RequestMethod.GET)
    @ResponseBody
    public List<EntitySubtype> getSchedulerEventTypes() throws ThingsboardException {
        try {
            SecurityUser user = getCurrentUser();
            TenantId tenantId = user.getTenantId();
            ListenableFuture<List<EntitySubtype>> schedulerEventTypes = schedulerEventService.findSchedulerEventTypesByTenantId(tenantId);
            return checkNotNull(schedulerEventTypes.get());
        } catch (Exception e) {
            throw handleException(e);
        }
    }
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/schedulerEvent/{schedulerEventId}", method = RequestMethod.DELETE)
    @ResponseStatus(value = HttpStatus.OK)
    public void deleteSchedulerEvent(@PathVariable(SCHEDULER_EVENT_ID) String strSchedulerEventId) throws ThingsboardException {
        checkParameter(SCHEDULER_EVENT_ID, strSchedulerEventId);
        try {
            SchedulerEventId schedulerEventId = new SchedulerEventId(toUUID(strSchedulerEventId));
            SchedulerEvent schedulerEvent = checkSchedulerEventId(schedulerEventId, Operation.DELETE);
            schedulerEventService.deleteSchedulerEvent(getCurrentUser().getTenantId(), schedulerEventId);
            defaultSchedulerSystem.onSchedulerEventChange(schedulerEvent,ActionType.DELETED);
            logEntityAction(schedulerEventId, schedulerEvent,
                    null,
                    ActionType.DELETED, null, strSchedulerEventId);
        } catch (Exception e) {

            logEntityAction(emptyId(EntityType.SCHEDULER_EVENT),
                    null,
                    null,
                    ActionType.DELETED, e, strSchedulerEventId);
            throw handleException(e);
        }
    }

    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/schedulerEventInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
    @ResponseBody
    public PageData<SchedulerEventInfo> getSchedulerEventInfos(@RequestParam int pageSize,
                                                             @RequestParam int page,
                                                             @RequestParam(required = false) String textSearch,
                                                             @RequestParam(required = false) String sortProperty,
                                                             @RequestParam(required = false) String sortOrder) throws ThingsboardException {
        try {
            PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
            TenantId tenantId = getCurrentUser().getTenantId();
            return checkNotNull(schedulerEventService.findSchedulerEventInfosByTenantId(tenantId, pageLink));
        } catch (Exception e) {
            throw handleException(e);
        }
    }

    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
    @RequestMapping(value = "/{customerId}/schedulerEventInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
    @ResponseBody
    public PageData<SchedulerEventInfo> getSchedulerEventInfosByCustomerId(
            @PathVariable("customerId") String strCustomerId,
            @RequestParam int pageSize,
            @RequestParam int page,
            @RequestParam(required = false) String textSearch,
            @RequestParam(required = false) String sortProperty,
            @RequestParam(required = false) String sortOrder) throws ThingsboardException {
        checkParameter("customerId", strCustomerId);
        try {
            TenantId tenantId = getCurrentUser().getTenantId();
            CustomerId customerId = new CustomerId(toUUID(strCustomerId));
            checkCustomerId(customerId, Operation.READ);
            PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
            return checkNotNull(schedulerEventService.findSchedulerEventInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink));
        } catch (Exception e) {
            throw handleException(e);
        }
    }

}
